package com.market.plus.core.mapping.impl;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.PropertyAccessor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import com.googlecode.simpleobjectassembler.ObjectAssembler;
import com.googlecode.simpleobjectassembler.beans.FallbackPropertyAccessor;
import com.market.plus.core.domain.Avatar;
import com.market.plus.core.domain.News;
import com.market.plus.core.domain.Participant;
import com.market.plus.core.domain.Relationship;
import com.market.plus.core.domain.Tribe;
import com.market.plus.core.dto.AvatarDto;
import com.market.plus.core.dto.NewsDto;
import com.market.plus.core.dto.ParticipantDto;
import com.market.plus.core.dto.RelationshipDto;
import com.market.plus.core.dto.TribeDto;
import com.market.plus.core.mapping.DTOConfiguration;
import com.market.plus.core.mapping.DTOService;
import com.market.plus.core.mapping.MappingConfigure;

@Service("marketDtoService")
public class DTOServiceImpl implements DTOService {

   private ObjectAssembler objectAssembler;

   private MappingConfigure mappingConfigure;

   @Autowired
   public DTOServiceImpl(@Qualifier("marketObjectAssembler") CustomObjectAssembler objectAssembler,
         @Qualifier("marketMappingConfigure") MappingConfigure mappingConfigure) {
      this.objectAssembler = objectAssembler;
      this.mappingConfigure = mappingConfigure;
   }

   private DTOConfiguration createDTOMappingConfigure(DTOConfiguration dtoMappingConfigure) {
      if (dtoMappingConfigure == null)
         dtoMappingConfigure = DTOConfiguration.instance();

      return dtoMappingConfigure;
   }

   public ParticipantDto convertParticipantDto(Participant participant, DTOConfiguration dtoMappingConfigure) {
      dtoMappingConfigure = createDTOMappingConfigure(dtoMappingConfigure);
      String[] excludedProperties = mappingConfigure.getPropertiesExcluding(dtoMappingConfigure.getIdMapping());
      ParticipantDto participantDto = objectAssembler.assemble(participant, ParticipantDto.class, excludedProperties);
      return participantDto;
   }

   public String[] getExcludes(DTOConfiguration configuration) {
      String[] excludedProperties = mappingConfigure.getPropertiesExcluding(configuration.getIdMapping());
      return excludedProperties;
   }

   public List<ParticipantDto> convertParticipantDtos(List<Participant> participants,
         DTOConfiguration dtoMappingConfigure) {
      List<ParticipantDto> participantDtos = new ArrayList<ParticipantDto>();
      for (Participant participant : participants){
         participantDtos.add(convertParticipantDto(participant, dtoMappingConfigure));
      }
      return participantDtos;
   }

   public NewsDto convertNewsDto(News news, DTOConfiguration dtoMappingConfigure) {
      dtoMappingConfigure = createDTOMappingConfigure(dtoMappingConfigure);
      String[] excludedProperties = mappingConfigure.getPropertiesExcluding(dtoMappingConfigure.getIdMapping());
      NewsDto newsDto = objectAssembler.assemble(news, NewsDto.class, excludedProperties);
      return newsDto;
   }

   public List<NewsDto> convertNewsDto(List<News> news, DTOConfiguration dtoMappingConfigure) {
      List<NewsDto> newsDtos = new ArrayList<NewsDto>();
      for (News selectedNews : news){
         newsDtos.add(convertNewsDto(selectedNews, dtoMappingConfigure));
      }
      return newsDtos;
   }

   public AvatarDto convertAvatarDto(Avatar avatar, DTOConfiguration dtoMappingConfigure) {
      dtoMappingConfigure = createDTOMappingConfigure(dtoMappingConfigure);
      String[] excludedProperties = mappingConfigure.getPropertiesExcluding(dtoMappingConfigure.getIdMapping());
      AvatarDto avatarDto = objectAssembler.assemble(avatar, AvatarDto.class, excludedProperties);
      return avatarDto;
   }

   public <T> List<T> convertTypeCollection(List<?> objectDtos, Class<T> destinationObject, String parentPropertyName, Object parent, String... ignoreProperties){
      List<T> properties = new ArrayList<T>();
      for (Object sourceObject : objectDtos){
         T objectT = this.objectAssembler.assemble(sourceObject, destinationObject, ignoreProperties);
         PropertyAccessor destinationPropertyAccessor = new FallbackPropertyAccessor(objectT);
         destinationPropertyAccessor.setPropertyValue(parentPropertyName, parent);
         properties.add(objectT);
      }
      return properties;
   }

   public TribeDto convertTribeDto(Tribe tribe, DTOConfiguration dtoMappingConfigure) {
      dtoMappingConfigure = createDTOMappingConfigure(dtoMappingConfigure);
      String[] excludedProperties = mappingConfigure.getPropertiesExcluding(dtoMappingConfigure.getIdMapping());
      TribeDto dto = objectAssembler.assemble(tribe, TribeDto.class, excludedProperties);
      return dto;
   }

   public RelationshipDto convertRelationshipDto(Relationship relationship,DTOConfiguration dtoMappingConfigure) {
      dtoMappingConfigure = createDTOMappingConfigure(dtoMappingConfigure);
      String[] excludedProperties = mappingConfigure.getPropertiesExcluding(dtoMappingConfigure.getIdMapping());
      RelationshipDto dto = objectAssembler.assemble(relationship, RelationshipDto.class, excludedProperties);
      return dto;
   }

   public List<RelationshipDto> convertRelationshipDtos(List<Relationship> relationships,
         DTOConfiguration dtoMappingConfigure) {
      List<RelationshipDto> relationshipDtos = new ArrayList<RelationshipDto>();
      for (Relationship relationship : relationships){
         RelationshipDto relationshipDto = convertRelationshipDto(relationship, dtoMappingConfigure);
         relationshipDtos.add(relationshipDto);
      }
      return relationshipDtos;
   }
}
